#pragma warning disable CA5394 // Do not use insecure randomness

namespace MoreLinq;

using System;
#if !NET6_0_OR_GREATER
    using System.Threading;
#endif

public static partial class MoreEnumerable
{
    /// <remarks>
    /// <see cref="System.Random"/> is not thread-safe so the following
    /// implementation uses thread-local <see cref="System.Random"/>
    /// instances to create the illusion of a global
    /// <see cref="System.Random"/> implementation. For some background,
    /// see <a href="https://blogs.msdn.microsoft.com/pfxteam/2009/02/19/getting-random-numbers-in-a-thread-safe-way/">Getting
    /// random numbers in a thread-safe way</a>.
    /// On .NET 6+, delegates to <c>Random.Shared</c>.
    /// </remarks>

    partial class GlobalRandom { }

#if NET6_0_OR_GREATER
    static partial class GlobalRandom
    {
        public static Random Instance => System.Random.Shared;
    }
#else // NET6_0_OR_GREATER
        sealed partial class GlobalRandom : Random
        {
            public static Random Instance { get; } = new GlobalRandom();

            static int seed = Environment.TickCount;
            [ThreadStatic] static Random? threadRandom;
            static Random ThreadRandom => threadRandom ??= new Random(Interlocked.Increment(ref seed));

            GlobalRandom() { }

            public override int Next() => ThreadRandom.Next();
            public override int Next(int minValue, int maxValue) => ThreadRandom.Next(minValue, maxValue);
            public override int Next(int maxValue) => ThreadRandom.Next(maxValue);
            public override double NextDouble() => ThreadRandom.NextDouble();
            public override void NextBytes(byte[] buffer) => ThreadRandom.NextBytes(buffer);

            protected override double Sample()
            {
                // All the NextXXX calls are hijacked above to use the Random
                // instance allocated for the thread so no call from the base
                // class should ever end up here. If Random introduces new
                // virtual members in the future that call into Sample and
                // which end up getting used in the implementation of a
                // randomizing operator from the outer class then they will
                // need to be overriden.

                throw new NotImplementedException();
            }
        }
#endif // NET6_0_OR_GREATER
}
